﻿'use strict';

let Imap;
let imap;
let imap_ready = false;

let effective_mailuser;
let effective_mailpass;
let imap_host;
let imap_port;
let imap_secure;
let imap_rejectunauth;
let smtp_host;
let smtp_port;
let smtp_secure;
let smtp_rejectunauth;
let smtp_pass;
let stored_mailStartUID;
let maildebug; // 逻辑值

const fs = require('fs');

process.on('message', (msg) => {
    if (msg.run == 'SendMail') {
	effective_mailuser = msg.user;
	effective_mailpass = msg.pass;
	smtp_host = msg.smtphost;
	smtp_port = msg.smtpport;
	smtp_secure = (msg.smtpsecure != 0);
	smtp_rejectunauth = (msg.smtprejectunauth != 0);
	smtp_pass = msg.smtppass;

	//// 通知父进程显示信息
	//process.send ({ event:	'info',
	//		txt:	'调试输出 msg 结构: ' +
	//			JSON.stringify(msg),
	//		state:	'' });
	let sendmail;
	let nodemailer;
	let transporter;
	let to = msg.recipient;
	if (! /@/.test(to)) {	// 发往 Ethereal 邮箱
	    // silent 须为 true；否则 nw-0.14.7 在 XP 下死于 console 输出
	    sendmail = require('./node-sendmail/sendmail')({silent: true});
	    to += '@ethereal.email';
	} else {		// 发往普通邮箱
	    nodemailer = require('./nodemailer/lib/nodemailer');
	    transporter = nodemailer.createTransport({
		host: smtp_host, // 'smtp.ethereal.email'
		port: smtp_port, // 465,
		secure: smtp_secure, //true, // use TLS
		auth: {
		    user: effective_mailuser,
		    pass: smtp_pass,
		},
		tls: {
		    rejectUnauthorized: smtp_rejectunauth,
			//false, // do not fail on invalid certs
		},
	    });

	    sendmail = function (data, cb) {
		transporter.sendMail(data, cb);
	    };
	}
	let str = msg.str.split('\0');
	let text = str[0];
	let i = 1;
	if (! str[0] && str[1] == 'cipher') {
	    text = '\0cipher\0' + str[2];
	    i = 3;
	}
	let attachments = [];
	for (; i < str.length; i++) {
	    let path = str[i];
	    if (! fs.existsSync(path))
		continue;
	    let stat = fs.statSync(path);
	    if (! stat.isFile())
		continue;
	    let time = Math.floor(stat.mtime.getTime() / 1000);
	    //let filename = str[i];
	    //if (/^\.\.\/shared\//.test(str[i])) {
		//filename = str[i].replace(/^\.\.\/shared\/[^\/]*\//, '');
	    //} else {
		//filename = str[i].replace(/^.*[:\/]/, '');
	    //}
	    let filename = str[i].replace(/^.*[:\/]/, '');
	    filename = '=?UTF-8?B?' +
			Buffer.from(filename).toString('base64')
			+ '?=';

	    // cid 包含文件最后修改时间(hex秒)以及文件的 dir 部分(hex编码)
	    // 两者之间用 '.' 分隔。
	    // dir 部分应以 sync/ 开头, 不含文件名, 并以 '/' 结尾,
	    // 否则 dir 部分应为空。

	    let dir = '';
	    let cid = time.toString(16) + '.';
	    if (/^\.\.\/shared\//.test(str[i])) {
		dir = str[i].replace(/^\.\.\/shared\/[^\/]*\//, '')
			.replace(/[^\/]*$/, '');
	    }
	    if (dir)
		cid += Buffer.from(dir).toString('hex');
	    attachments.push({
		filename: filename,
		path:	path,
		cid:	cid
	    });
	}
	let message = {
		from:		msg.sender + ' <' + effective_mailuser + '>',
		to:		to,
		subject:	msg.subject,
		html:		text,
		attachments:	attachments
	};
	sendmail (message, function (err, reply) {
		// 通知父进程发邮件结束, 让父进程执行 callback
		process.send ({
			event: 'sent',
			txt:   err ? ' 邮寄失败: ' + err.stack
				   : ' 邮寄成功。MX 服务器响应: ' +
					JSON.stringify(reply),
			state: err
		});
		// 通知父进程本子进程退出
		process.send ({ event: 'exit', state: '' });
		setTimeout (() => { process.exit(); }, 1000);
	});
	return;
    }
    if (msg.run == 'imapConnect') {
	effective_mailuser = msg.user;
	effective_mailpass = msg.pass;
	smtp_pass = msg.smtppass;
	imap_host = msg.imaphost;
	imap_port = msg.imapport;
	imap_secure = (msg.imapsecure != 0);
	imap_rejectunauth = (msg.imaprejectunauth != 0);
	stored_mailStartUID = msg.mailUID;
	maildebug = msg.maildebug;
	imapConnect ();
	return;
    }
    if (msg.run == 'imap.end') {
	effective_mailuser = msg.user;
	effective_mailpass = msg.pass;
	if (typeof imap !== 'undefined') {
		imap.end ();
		imap.end ();
	}
	// 通知父进程本子进程退出
	process.send ({
		event: 'exit',
		state: ''
	});
	setTimeout (() => { process.exit(); }, 1000);
	return;
    }
    if (msg.run == 'update.uid') {
	stored_mailStartUID = msg.uid;
	return;
    }
    if (msg.run == 'update.maildebug') {
	maildebug = msg.maildebug;
	return;
    }
});

    // 返回文件夹 ../shared/mailbox 中的一个以 file 开头的可用文件名
    function createdir_renamefile(file) {
	// 若不存在文件夹, 先创建它
	if (fs.existsSync('../shared')) {
		if (! fs.statSync('../shared').isDirectory()) {
		    // 它不是文件夹, 先重命名它, 再创建它
		    let h;
		    try {
			h = fs.mkdtempSync('../shared.');
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '创建临时文件夹 shared.* 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		    // 先删除 h, 然后才能重命名为 h
		    try {
			fs.rmdirSync(h);
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '删除临时文件夹 ' + h + ' 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		    try {
			fs.renameSync('../shared', h);
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '重命名 ../shared 为 ' + h + ' 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		    try {
			fs.mkdirSync('../shared');
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '创建文件夹 ../shared 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		}
	} else {
		try {
		    fs.mkdirSync('../shared');
		} catch (e) {
		    // 通知父进程显示信息
		    process.send ({
			event: 'info',
			txt: '创建文件夹 ../shared 失败。' + e,
			state: imap.state
		    });
		    return false;
		}
	}
	if (fs.existsSync('../shared/mailbox')) {
		if (! fs.statSync('../shared/mailbox').isDirectory()) {
		    // 它不是文件夹, 先重命名它, 再创建它
		    let h;
		    try {
			h = fs.mkdtempSync('../shared/mailbox.');
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '创建文件夹 shared/mailbox.* 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		    // 先删除 h, 然后才能重命名为 h
		    try {
			fs.rmdirSync(h);
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '删除临时文件夹 ' + h + ' 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		    try {
			fs.renameSync('../shared/mailbox', h);
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '重命名 ../shared/mailbox 为 ' + h +
				 ' 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		    try {
			fs.mkdirSync('../shared/mailbox');
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '创建文件夹 ../shared/mailbox 失败。' + e,
			    state: imap.state
			});
			return false;
		    }
		}
	} else {
		try {
		    fs.mkdirSync('../shared/mailbox');
		} catch (e) {
		    // 通知父进程显示信息
		    process.send ({
			event: 'info',
			txt: '创建文件夹 ../shared/mailbox 失败。' + e,
			state: imap.state
		    });
		    return false;
		}
	}
	// 若文件已存在, 创建临时文件
	if (fs.existsSync(file)) {
		let h;
		try {
		    h = fs.mkdtempSync(file + '.');
		} catch (e) {
		    // 通知父进程显示信息
		    process.send ({
			event: 'info',
			txt: '创建临时文件夹 ' + file +
			     '.?????? 失败, 无法接收邮件附件。' + e,
			state: imap.state
		    });
		    return false;
		}
		// 先删除文件夹 h, 然后才能创建文件 h
		try {
		    fs.rmdirSync(h);
		} catch (e) {
		    // 通知父进程显示信息
		    process.send ({
			event: 'info',
			txt: '删除临时文件夹 ' + h +
			     ' 失败, 无法接收邮件附件。' + e,
			state: imap.state
		    });
		    return false;
		}
		return h;
	}
	return file;
    } // 函数 createdir_renamefile() 定义结束

    let fetch_mail_counter = 0;
    let fetch_mail_busy = 0;
    let mailbox_opened = false;
    let last_fetch_time = 0;

    // 定义函数，创建 imap 对象

    function create_imap () {
	if (typeof imap !== 'undefined')
		return;

	Imap = require('./node-imap');
	imap = new Imap({
		user: effective_mailuser,
		password: smtp_pass ? smtp_pass : effective_mailpass,
		host: imap_host, //'imap.ethereal.email',
		port: imap_port, //993
		// 对 ethereal 来说, tls 应设为 true
		// 若 tls 设为 false, 可避免 crash, 但会认证失败
		tls: imap_secure,
		tlsOptions: { rejectUnauthorized: imap_rejectunauth }
	});

	imap.on ('error', function (err) {
	    // 向父进程报告 imap 错误
	    process.send ({
			event: 'error',
			errStr: err.toString(),
			errSrc: err.source,
			state: imap.state
	    });
	});

	imap.on ('end', function () {
	    // 向父进程报告 imap 连接终止
	    process.send ({
			event: 'end',
			state: imap.state
	    });
	});

	imap.on ('close', function (haderr) {
	    // 向父进程报告 imap 连接关闭
	    process.send ({
			event: 'close',
			err: haderr,
			state: imap.state
	    });
	});

	imap.on ('alert', function (msg) {
	    // 向父进程报告 imap 服务器发出警告
	    process.send ({
			event: 'alert',
			err: msg,
			state: imap.state
	    });
	});

	imap.on ('ready', function () {
	    imap_ready = true;
	    // 通知父进程显示信息
	    process.send ({
			event: 'info',
			txt: '成功连接到收件服务器。检查新邮件……',
			state: imap.state
	    });

	    // 设置 fetch 计数，让 imapConnect () 去执行 fetch_mail ()
	    if (fetch_mail_counter <= 0)
		fetch_mail_counter = 1;
	    if (fetch_mail_busy === 1)
		fetch_mail_counter = 2;
	    imapConnect ();
	});

	imap.on ('mail', function (n) {
	    //// 通知父进程显示信息
	    //process.send ({
		//	event: 'info',
		//	txt: '收到 ' + n + ' 条消息。检查未读消息……',
		//	state: imap.state
	    //});

	    // 设置 fetch 计数，让 imapConnect () 去执行 fetch_mail ()
	    if (fetch_mail_counter <= 0)
		fetch_mail_counter = 1;
	    if (fetch_mail_busy === 1)
		fetch_mail_counter = 2;
	    imapConnect ();
	});
    } // create_imap () 函数定义结束

    // 定义函数，查找未读邮件

    function search_unseen () {
	// 查找未读邮件
	imap.search (//['UNSEEN'],
		[ ['UID', ((! stored_mailStartUID || 
			stored_mailStartUID == 'null') ?
			1 : stored_mailStartUID) + ':*' ] ],
		function (err, results) {
	    // 如果查找出错，视为“未找到”，结束处理
	    if (err) {
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '查找邮件出错: ' + err + ' 状态: ',
			state: imap.state
		});
		mailbox_opened = false;
		// closeBox() 使某台 ARM64 下的 nw 崩溃
		if (typeof nw !== 'object') { // 只在 electron 时执行
		    imap.closeBox (function (err1) {
			if (err1)
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱失败: ' + err1 + ' 状态: ',
				state: imap.state
			    });
			else
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱成功。',
				state: imap.state
			    });
		    });
		}
    		fetch_mail_counter --;
		// 清除“忙”标志，允许后续的 fetch。
	       	fetch_mail_busy = 0;
		// 执行 imapConnect () 函数, 目的是在必要时建立连接,
		// 以及执行队列中的 fetch
		imap.end();
		imapConnect ();
		return;
	    }
	    // 若 results 不是数组, 调试输出详细信息
	    if (! Array.isArray(results)) {
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '严重错误: results 不是数组!' +
			     ' typeof results = ' + (typeof results) +
			     ' 内容为: ' + JSON.stringify(results)
					.replace(/</g, '&lt;')
					.replace(/>/g, '&gt;') + '(内容完)',
			state: imap.state
		});
		// 异常情况, 按照“没有邮件”来处理, 引起用户注意。
		// 也可以忽略这个异常情况, 注释掉后续内容直到 return
		// 语句（连 return 语句也一同注释掉）。
	
		// 通知父进程处理没有邮件的情况, 必要时调整邮件检查频率
		process.send ({
			event: 'no_mail',
			state: imap.state
		});

    		fetch_mail_counter --;
		// 清除“忙”标志，允许后续的 fetch。
	       	fetch_mail_busy = 0;
		// 执行 imapConnect () 函数, 目的是在必要时建立连接,
		// 以及执行队列中的 fetch
		imap.end();
		imapConnect ();
		return;
	    }
	    // 若没有未读邮件，结束处理
	    if (Array.isArray(results) && results.length == 0) {
		// 通知父进程处理没有邮件的情况, 必要时调整邮件检查频率
		process.send ({
			event: 'no_mail',
			state: imap.state
		});

		// （此处若关闭邮箱，会导致 mail 事件不发送）
    		fetch_mail_counter --;
		// 清除“忙”标志，允许后续的 fetch 操作。
	       	fetch_mail_busy = 0;
		// 执行 imapConnect () 函数, 目的是在必要时建立连接,
		// 以及执行正在等待的 fetch 操作。
		imapConnect ();
		return;
	    }

	    // results 是 UID 数组, 因此，针对数组的单个 UID 元素进行 fetch,
	    // 可以准确知道正在抓取的邮件的 UID 值

	    // bodies: 'TEXT'
	    // bodies: ['HEADER.FIELDS (FROM)','TEXT']
	    // bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)'

	    let fetch_error = false;
function do_next_uid (j) {
	    if (fetch_error)
		return;
	    let uid = results[j];
	    let uid_file = '../shared/mailbox/' + effective_mailuser +
				'.' + uid + '.eml';
	function removefile_exitprocess () {
		// 取回的邮件数据不可靠, 删除它
		if (fs.existsSync(uid_file)) {
		    try {
			fs.unlinkSync(uid_file);
		    } catch (e) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '删除文件 ' + uid_file +
				 ' 失败，请手动删除这个无效文件。' + e,
			    state: imap.state
			});
		    }
		}

		// 取邮件失败可能意味着服务器端异常, 应退出进程, 下次再试

		// 通知父进程本子进程退出
		process.send ({
			event: 'exit',
			state: imap.state
		});
		//process.exit();
		// TODO: 验证 electron 是否支持 process.exit()
		// 1 秒后关闭收件箱
		setTimeout (() => {
			imap.closeBox (function (err) {});
		}, 1000);
		// 3 秒后断开连接
		setTimeout (() => {
			imap.end();
		}, 3000);
		// 5 秒后退出进程
		setTimeout (() => {
			process.exit(0);
		}, 5000);
	}

	function fetch_end () {
		if (j + 1 < results.length) {
		    setTimeout(do_next_uid, 5000, j + 1);
		    return;
		}
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '已取回全部邮件。',
			state: imap.state
		});
		// 取回全部邮件后, 把它们标记为: 已读
		imap.setFlags (results, ['\\Seen'], function (err) {
		    if (err)
			// 通知父进程显示信息
			process.send ({
				event: 'info',
				txt: '标记邮件已读失败: ' + err + ' 状态: ',
				state: imap.state
			});
		    else
			// 通知父进程显示信息
			process.send ({
				event: 'info',
				txt: '成功标记邮件已读。',
				state: imap.state
			});
	        });
		// （此处若关闭邮箱会导致 mail 事件不发送）
    		fetch_mail_counter --;
		// 清除“忙”标志，允许后续的 fetch。
	       	fetch_mail_busy = 0;
		// 执行 imapConnect () 函数, 目的是在必要时建立连接,
		// 以及执行队列中的 fetch
		imapConnect ();
	}
	    // 若文件已存在, 跳过
	    if (fs.existsSync(uid_file)) {
		// 通知父进程显示信息
		process.send ({
		    event: 'info',
		    txt: '跳过已收取的邮件, uid ' + uid,
		    state: imap.state
		});
		// 必要时通知父进程更新 uid 记录
		if (! stored_mailStartUID ||
			stored_mailStartUID < uid + 1) {
			stored_mailStartUID = uid + 1;
			// 通知父进程记录 uid
			process.send ({
			    event: 'uid',
			    uid:	uid,
			    state: imap.state
			});
		}
		if (j + 1 >= results.length) {
		    // 这是最后一个邮件, 且先前已收取过, 这表明没有新邮件。
		    // 通知父进程没有新邮件, 以便父进程调整邮件检查频率
		    process.send ({
			event: 'no_mail',
			state: imap.state
		    });
		}
		fetch_end ();
		return;
	    }
	    let f = imap.fetch ([uid], {
		//bodies:['HEADER.FIELDS (FROM TO SUBJECT DATE)','TEXT'],
		bodies: '',
	       	markSeen: false, // 不标记已读, 等成功获取邮件后再标记
		//struct: true
	    });

	    f.on ('message', function (msg, seqno) {
		var prefix = '<br/>(#' + seqno + ') ';
		var header, from, to, subj, date, text;

		// const inspect = require('util').inspect;
		//var mailparser = new MailParser();
		msg.on ('body', function (stream, info) {
		    let file = createdir_renamefile(uid_file);
		    if (! file) {
			// 无法写文件, 退出, 已通知父进程显示具体错误
			return;
		    }
		    let fileWriteStream = fs.createWriteStream(file);
		    fileWriteStream.on('error', (err) => {
			fileWriteStream.end();
			// 文件已经不可靠, 应删除
			// 虽然后续的文件可能会成功抓取, 但我们处理邮件
			// 是按顺序的，不可以跳过一个邮件。因此, 这里应
			// 退出子进程, 下次再试
			fetch_error = true; // 阻止 do_next_uid() 的执行
			setTimeout (removefile_exitprocess, 2000);
		    });
		    fileWriteStream.on('close', () => {
			//fileWriteStream.end();
			if (fetch_error)
			    return;
			//通知父进程解析邮件
			process.send ({
			    event: 'parse',
			    eml:	uid_file,
			});
		    });
		    stream.pipe(fileWriteStream);
		    return;
		});

		msg.once ('attributes', function (attrs) {
		    if (attrs.uid != uid) {
			// 通知父进程显示信息
			process.send ({
			    event: 'info',
			    txt: '异常! attrs.uid=' + attrs.uid + ' 与 uid='
				 + uid + '不同! ',
			    state: imap.state
			});
		    }
		    if (! stored_mailStartUID ||
			  stored_mailStartUID == 'null' ||
			  stored_mailStartUID < attrs.uid + 1) {
			stored_mailStartUID = attrs.uid + 1;
			// 通知父进程记录 uid
			process.send ({
			    event: 'uid',
			    uid:	attrs.uid,
			    state: imap.state
			});
		    }
		});
		msg.once ('end', function() {
		    // 通知父进程显示信息
		    process.send ({
			event: 'info',
			txt: '取完第 ' + seqno + ' 条消息。uid ' + uid,
			state: imap.state
		    });
		});
	    }); // f.on 'message' 事件处理结束

	    f.once ('error', function (err) {
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '取邮件（uid=' + uid + '）时出错: ' + err,
			state: imap.state
		});
		
		fetch_error = true; // 阻止 do_next_uid() 的执行
		setTimeout (removefile_exitprocess, 2000);
		return Promise.reject (err); // 相当于注释掉后续代码

		mailbox_opened = false;
		// closeBox() 使某台 ARM64 下的 nw 崩溃
		if (typeof nw !== 'object') { // 只在 electron 时执行
		    imap.closeBox (function (err1) {
			if (err1)
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱失败: ' + err1,
				state: imap.state
			    });
			else
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱成功。',
				state: imap.state
			    });
		    });
		}
    		fetch_mail_counter --;
		// 清除“忙”标志，允许后续的 fetch。
	       	fetch_mail_busy = 0;
		// 执行 imapConnect () 函数, 目的是在必要时建立连接,
		// 以及执行队列中的 fetch
		imap.end();
		imapConnect ();
		return Promise.reject (err);
	    }); // f.once 'error' 事件处理结束

	    f.once ('end', fetch_end);
}
	    do_next_uid(0);
	}); // 查找未读邮件结束
    } // search_unseen () 函数定义结束

    // 定义函数，抓取邮件
    function fetch_mail () {

	// 前一个 fetch 刚完成不超过 15 秒，取消本次 fetch。
	if (Date.now() - last_fetch_time <= 15000) {
	    return;
	}
	last_fetch_time = Date.now();

	// 前一个 fetch 未完成，后续的 fetch 要等待。
	if (fetch_mail_busy)
	    return;

       	fetch_mail_busy = 1;	// 设置-忙-标志, 阻塞后续的 fetch

	//// 通知父进程显示信息
	//process.send ({
	//	event: 'info',
	//	txt: '查找邮件……',
	//	state: imap.state
	//});

	if (mailbox_opened) {
	    search_unseen ();
	    return;
	}
	imap.openBox ('INBOX', false, function (err, box) {
	    if (err) {	// 打开邮箱失败，断开并重新连接
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '打开邮箱失败: ' + err,
			state: imap.state
		});
		// （此处若执行 closeBox 会抛出异常）

		fetch_mail_counter --;
	       	fetch_mail_busy = 0;	// 清除-忙-标志, 允许后续的 fetch
		imap.end();		// 断开连接
		imapConnect ();		// 建立连接并执行等待中的 fetch
		return;
	    }
	    mailbox_opened = true;
	    search_unseen ();
	}); // 打开收件箱结束
    } // fetch_mail () 函数定义结束

    // 函数定义，连接 IMAP 收件服务器
    function imapConnect () {

	create_imap ();
	if (typeof imap === 'undefined')
	    return;

	if (imap.state === 'authenticated') {
	    if (fetch_mail_counter > 0) {
		//// 通知父进程显示信息
		//process.send ({
		//	event: 'info',
		//	txt: '邮箱状态已变。检查未读消息……',
		//	state: imap.state
		//});
		fetch_mail ();
	    } else if (Date.now() - last_fetch_time > 15000) {
		fetch_mail_counter = 1;
		fetch_mail ();
	    } else {
		//debug_info.insertAdjacentHTML ('beforeEnd', Date() +
		//	' 邮箱状态未变，不必检查邮件。<br/>');
	    }
	    return;
	}

	// 如果连接成功后失败，再次连接之前，需要结束子进程，启动新子进程
	if (imap_ready) {
	    // 通知父进程本子进程退出
	    process.send ({
			event: 'exit',
			state: imap.state
	    });
	    //process.exit();
	    setTimeout (() => { process.exit(0); }, 1000);
	    return;
	}

	if (imap.state === 'connected') {
	    // 通知父进程显示信息
	    process.send ({
			event: 'info',
			txt: 'IMAP 已连接，但邮箱登录失败。断开并重连……',
			state: imap.state
	    });
	    if (mailbox_opened) {
		mailbox_opened = false;
		// closeBox() 使某台 ARM64 下的 nw 崩溃
		if (typeof nw !== 'object') { // 只在 electron 时执行
		    imap.closeBox (function (err) {
			if (err)
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱失败: ' + err,
				state: imap.state
			    });
			else
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱成功。',
				state: imap.state
			    });
		    });
		}
	    }
	    // 通知父进程显示信息
	    process.send ({
			event: 'info',
			txt: '断开连接……',
			state: imap.state
	    });
	    imap.end ();
	    // 通知父进程显示信息
	    process.send ({
			event: 'info',
			txt: '重新连接……',
			state: imap.state
	    });
	    fetch_mail_busy = 0; // 在重新连接之前，清除忙位
	} else { // disconnected
	    // 通知父进程显示信息
	    process.send ({
			event: 'info',
			txt: 'IMAP 未连接。正在连接……',
			state: imap.state
	    });
	    fetch_mail_busy = 0; // 在重新连接之前，清除忙位
	    if (mailbox_opened) {
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '邮箱处于打开状态。先关闭邮箱……',
			state: imap.state
		});
		mailbox_opened = false;
		// closeBox() 使某台 ARM64 下的 nw 崩溃
		if (typeof nw !== 'object') { // 只在 electron 时执行
		    imap.closeBox (function (err) {
			if (err)
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱失败: ' + err,
				state: imap.state
			    });
			else
			    // 通知父进程显示信息
			    process.send ({
				event: 'info',
				txt: '关闭邮箱成功。',
				state: imap.state
			    });
		    });
		}
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '断开连接……',
			state: imap.state
		});
		imap.end ();
		// 通知父进程显示信息
		process.send ({
			event: 'info',
			txt: '重新连接……',
			state: imap.state
		});
	    }
	}
	imap.connect ();

    } // imapConnect () 函数定义结束

